package cn.cdeden.resource.easyes.util;

/**
 * @ProjectName : KnowCore
 * @Package : cn.cdeden.resource.service
 * @ClassName : EsDataOperation
 * @Author : Yu.
 * @Description : // TODO
 * @Date : 2024/12/10 19:30
 * @Version : 1.0
 */

import cn.cdeden.common.elasticsearch.index.EsIndexesInfo;
import com.alibaba.fastjson2.JSONObject;
import com.fasterxml.jackson.core.exc.StreamConstraintsException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.action.DocWriteRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.support.WriteRequest;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.client.HttpAsyncResponseConsumerFactory;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.client.indices.GetIndexResponse;
import org.elasticsearch.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.List;
import java.util.Map;


/**
 * 增删改数据
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
@ConditionalOnProperty(value = "easy-es.enable", havingValue = "true")
public class EsDataOperation {

    private final RestHighLevelClient client;
    private static  final RequestOptions options ;

    static {
        RequestOptions.Builder builder = RequestOptions.DEFAULT.toBuilder();
        // 默认缓冲限制为100MB，此处修改为500MB。
        builder.setHttpAsyncResponseConsumerFactory(
            new HttpAsyncResponseConsumerFactory.
            HeapBufferedResponseConsumerFactory(500 * 1024 * 1024)
        );
        options = builder.build();
    }



    /**
     * 判断索引是否存在
     * @author Yu.
     * @Date 2024/12/13 9:50
     * @param indexName
     * @return boolean
     **/
    public boolean indexExists(String indexName)  {
        GetIndexRequest request = new GetIndexRequest(indexName);
        boolean exists;
        try {
            GetIndexResponse response = client.indices().get(request, options);
            exists = response.getAliases().isEmpty() == false;
        } catch (ElasticsearchException e) {
            // 如果索引不存在，会抛出ElasticsearchException，我们捕获它并返回false
            exists = false;
        } catch (IOException e) {
            // 链接异常也是错误，直接返回false
            exists = false;
        }
        return exists;
    }


    /**
     *
     * @author Yu.
     * @Description //  创建索引
     * @Date 2024/12/13 9:53
     * @param indexName
     * @return boolean
     **/
    public boolean indexCreate(String indexName){
        try {
            if (indexExists(indexName)) {
                return true;
            }else  {
                String string = EsIndexesInfo.getIndexName(indexName);
                JSONObject jsonObject = JSONObject.parseObject(string);
                CreateIndexRequest request = new CreateIndexRequest(indexName);
                //设置DSL语句,第一个参数为构建mapping的json语句，第二个参数是表明这是JSON数据格式
                request.source(EsIndexesInfo.MAPPING_TEMPLATE, XContentType.JSON);
//                request.mapping("_doc",EsIndexesInfo.MAPPING_TEMPLATE, XContentType.JSON);
//                request.mapping(EsIndexesInfo.MAPPING_TEMPLATE, XContentType.JSON);
//                request.source(jsonObject, LoggingDeprecationHandler.INSTANCE);
                //发起请求
                CreateIndexResponse result = client.indices().create(request, options);
                boolean isSuccess = result.isAcknowledged();
                System.out.println(isSuccess?"构建索引库成功":"构建索引库失败");
                return isSuccess;
            }
        }catch (Exception e){
            log.error(e.getMessage(), e);
            throw new RuntimeException(e.getMessage());
        }

    }

    /**
     * 单条写入数据
     *
     * @param indexName 索引
     * @param dataMap   数据
     * @param pipeline  通道
     * @return boolean
     * @author Yu.
     * @Date 2024/12/11 10:45
     **/
    public boolean insert(String indexName, Map<String, Object> dataMap, String pipeline) {

//        boolean b = indexCreate(indexName);
        try {
            XContentType json = XContentType.JSON;
            IndexRequest create = null;
            if (dataMap.containsKey("id")) {
                create = new IndexRequest(indexName)
                    .opType(DocWriteRequest.OpType.INDEX)
                    .id(dataMap.get("id").toString())
                    .source(dataMap, json)
                    .setPipeline(pipeline);
            } else {
                create = new IndexRequest(indexName)
                    .opType(DocWriteRequest.OpType.INDEX)
                    .source(dataMap, json)
                    .setPipeline(pipeline);
            }
            BulkRequest request = new BulkRequest();
            request.add(create);
            this.client.bulk(request, options);
            return Boolean.TRUE;
        }catch (StreamConstraintsException e){
            dataMap.put("content",null);
            try {
                return insert( indexName,  dataMap, pipeline) ;
            }catch (Exception e1){
                throw new RuntimeException(e1.getMessage());
            }
        } catch (Exception e) {
            log.error("EsDataOperation insert error.", e);
            return Boolean.FALSE;
        }
    }


    /**
     * 批量写入数据
     *
     * @param indexName    索引
     * @param mapIndexList 数据
     * @param pipeline     通道
     * @return boolean
     * @author Yu.
     * @Date 2024/12/11 10:45
     **/
    public boolean batchInsert(String indexName, List<Map<String, Object>> mapIndexList, String pipeline) {
        try {
            BulkRequest request = new BulkRequest();
            for (Map<String, Object> dataMap : mapIndexList) {
                request.add(new IndexRequest(indexName)
//                    .opType("create")
                        .id(dataMap.get("id").toString())
                        .source(dataMap, XContentType.JSON)
                        .setPipeline(pipeline)
                );
            }
            this.client.bulk(request, options);
            return Boolean.TRUE;
        } catch (Exception e) {
            log.error("批量写入数据  error.", e);
        }
        return Boolean.FALSE;
    }

    /**
     * 根据id更新数据，可以直接修改索引结构
     *
     * @param refreshPolicy 数据刷新策略
     */
    public boolean update(String indexName, Map<String, Object> dataMap, WriteRequest.RefreshPolicy refreshPolicy) {
        try {
            UpdateRequest updateRequest = new UpdateRequest(indexName, dataMap.get("id").toString());
            updateRequest.setRefreshPolicy(refreshPolicy);
            for (String string : dataMap.keySet()) {
                Object o = dataMap.get(string);
                if (o == null) {
                    dataMap.remove(string);
                }
            }
            updateRequest.doc(dataMap);
            this.client.update(updateRequest, options);
            return Boolean.TRUE;
        } catch (Exception e) {
            log.error("EsDataOperation update error.", e);
        }
        return Boolean.FALSE;
    }

    /**
     * 删除数据
     */
    public boolean delete(String indexName, String id) {
        try {
            DeleteRequest deleteRequest = new DeleteRequest(indexName, id);
            this.client.delete(deleteRequest, options);
            return Boolean.TRUE;
        } catch (Exception e) {
//            log.error("EsDataOperation delete error.", e);
        }
        return Boolean.FALSE;
    }

    public Object queryContent(String content,Pageable pageable) {
        Integer page = pageable.getPageNumber();
        Integer size = pageable.getPageSize();
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery()
            .should(QueryBuilders.wildcardQuery("attachment.content", "*" + content + "*"))
            .should(QueryBuilders.wildcardQuery("fileName", "*" + content + "*"));

        // 添加管道聚合

        HighlightBuilder highlightBuilder = new HighlightBuilder();
        highlightBuilder.field("attachment.content"); //content字段高亮
        highlightBuilder.field("fileName");//fileName字段高亮
        highlightBuilder.preTags("<span style='color:red'>"); //高亮前缀
        highlightBuilder.postTags("</span>"); //高亮后缀
//        NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder()
//            //查询条件
//            .withQuery(boolQueryBuilder)
//            //分页
//            .withPageable(PageRequest.of(page, size))
//            //高亮字段显示
//            .withHighlightBuilder(highlightBuilder)
//            .build();

//        IndexCoordinates indexCoordinates = IndexCoordinates.of("personal");
//        SearchHits<Map> search = restTemplate.search(nativeSearchQuery, Map.class, indexCoordinates);
//        SearchHits<Object> search = searchHits;
//        SearchHits<Student> search = (SearchHits<Student>) searchHits;


        //数据列表：search.getSearchHits()  for出每一条，然后加到list中
//        List<SearchHit<Map>> searchHits = search.getSearchHits();
//        for (SearchHit<Map> searchHit : searchHits) {
//            System.out.println("单条文档的原数据 = " + searchHit.getContent());
//            System.out.println("单条文档的id = " + searchHit.getId());
//            System.out.println("单条文档的评分 = " + searchHit.getScore());
//            System.out.println("单条文档索引名（表名） = " + searchHit.getIndex());//298_ops-web-js_1就是你输入的索引库名
//        }
//        List<Student> docElasticsearchList = new ArrayList<>();
//        Long totalHits = search.getTotalHits();//匹配总条数，用于分页显示
//        for (SearchHit hit : searchHits){
//            //查询结果
//            com.alibaba.fastjson.JSONObject content1 = new com.alibaba.fastjson.JSONObject( (Map) hit.getContent());
//            Student student = content1.toJavaObject(Student.class);
////            docElasticsearchDto.setId(hit.getId());
//            //处理高亮字段
////            Map<String, HighlightField> map = ;
//            com.alibaba.fastjson.JSONObject highlightFields = new com.alibaba.fastjson.JSONObject(hit.getHighlightFields());
//
//
//            if(highlightFields.containsKey("attachment.content")) {
//
//                JSONArray jsonArray = highlightFields.getJSONArray("attachment.content");
//                StringBuilder matchContent = new StringBuilder();
//                for (int i = 0; i < jsonArray.size(); i++) {
//                    matchContent.append(jsonArray.getString(i));
//                }
//                student.setContent(matchContent.toString());
//            }else {
//                if (content1.containsKey("attachment")) {
//                    student.setContent(content1.getJSONObject("attachment").getString("content"));
//                }
//            }
//
//            if(highlightFields.containsKey("fileName")) {
//                StringBuilder matchFileName =  new StringBuilder();
//                JSONArray jsonArray = highlightFields.getJSONArray("fileName");
//                for (int i = 0; i < jsonArray.size(); i++) {
//                    matchFileName.append(jsonArray.getString(i));
//                }
//                student.setFileName(matchFileName.toString());
//            }
//            docElasticsearchList.add(student);
//        }

        return null;
    }


}
